/******************************************************************************
 *                  Shanghai ChipON Micro-Electronic Co.,Ltd
 ******************************************************************************
 *  @File Name        : kf8a100fxx_flash.c
 *  @Author           : ChipON AE/FAE Group
 *  @Date             : 2023-12-19
 *  @HW Version       : KF8A100Fxx
 *  @Lib Version      : V2.0.1
 *  @Description      : This file provides the driver for the flash module
 ******************************************************************************
 *  Copyright (C) by Shanghai ChipON Micro-Electronic Co.,Ltd
 *  All rights reserved.
 *
 *  This software is copyright protected and proprietary to
 *  Shanghai ChipON Micro-Electronic Co.,Ltd.
 *****************************************************************************/
/******************************************************************************
 *  |Date        |Version  |Author       |Description
 ******************************************************************************
 *  |2023-12-25  |V2.0     |Zhong Yusheng|New creat
 *****************************************************************************/

/******************************************************************************
 **                     QAC Warnings
 *****************************************************************************/
/* PRQA S 0436 EOF #8-bit MCU Features: Direct Write Registers. */
/* PRQA S 1291, 1820, 1821, 1822, 1823, 1851, 1853, 3715, 3757, 3760 EOF #Registers are essentially unsigned numbers. */
/* PRQA S 2754 EOF #Level 7 problem due to unsupported assembly instructions. */
/* PRQA S 3768, 3771, 4130, 4393, 4434, 4443, 4446, 4461, 4532 EOF #Registers are essentially unsigned numbers. */

/******************************************************************************
 *                      Include Files
 *****************************************************************************/
#include "kf8a100fxx_flash.h"
#include "DELAY.h"
/******************************************************************************
 *                      Macro Definitions
 *****************************************************************************/

/******************************************************************************
 *                      Constants
 *****************************************************************************/

/******************************************************************************
 *                      Type definitions
 *****************************************************************************/

/******************************************************************************
 *                      Variables
 *****************************************************************************/
/* PRQA S 3678,3218,3229,3232 2 # Used in assembly code. */
/* PRQA S 3408 2 # Internal variables, functions are not modified. */
uint16_t writeBuffer[FLASH_BUFFER_WORD_SIZE] = {0};
uint16_t readBuffer[FLASH_BUFFER_WORD_SIZE]  = {0};

volatile uint8_t Flash_Key_ONE, Flash_Key_TWO;
/******************************************************************************
 *                      Function definitions
 *****************************************************************************/

/**
 * @brief Data flash reads out a double byte of data at a specified address
 *
 * @param Addr flash addr: FLASH_ADDRESS_START~FLASH_ADDRESS_END and is a multiple of FLASH_EFFECTIVE_ADDRESS.
 * @return uint16_t flash data
 */
/* PRQA S 3206 1 # Used in assembly code. */
uint16_t FLASH_READ_ONE(uint16_t Addr)
{
    // clang-format off
/* Ignoring warnings for unused parameters and no results returned */
/* PRQA S 3116 3 # Assembly syntax. */
#pragma save
#pragma disable_warning 59
#pragma disable_warning 85
/* The compiler automatically variables STK00 and R0, where R0 is the high bit,
 * and returns using STK00 and R0, where R0 is the high bit */
	/* PRQA S 0289, 0899, 0451, 0873, 0780, 0782, 0911, 1277 ++ #Assembly code does not conform to C rules. */
    /* PRQA S 3110, 3112, 2000, 3202, 3109, 3139, 3417, 2015, 2214, 2753, 3426, 1842 ++ #assembly syntax. */
    /* PRQA S 2741 ++ #Control via macro definitions. */
	__asm
	BANKSEL _NVMADDRH
	MOV		_NVMADDRH,R0
	BANKSEL STK00
	MOV		R0,STK00
	BANKSEL _NVMADDRL
	MOV		_NVMADDRL,R0
	MOV		R1,_INTCTL
	CLR		_INTCTL,_AIE
	JNB		_INTCTL,_AIE
	JMP		$-2
	MOV 	R0,#0x81
	MOV 	_NVMCTL0,R0
	NOPZ
	NOPZ
	NOPZ
	NOPZ
	NOPZ
	NOPZ
	NOPZ
	NOPZ
	AND 	R1,#0xC0
	ORL 	_INTCTL,R1
	MOV		R0,_NVMDATAL
	BANKSEL STK00
	MOV		STK00,R0
	BANKSEL	_NVMDATAH
	MOV		R0,_NVMDATAH
	__endasm;
    /* PRQA S 0289, 0899, 0451, 0873, 0780, 0782, 0911, 1277, 3110, 3112, 2000, 2741, 3202, 3109, 3417, 3139-- */
        /* PRQA S 2015, 2214, 2753, 3426, 1842-- */
/* PRQA S 3116 3 # Assembly syntax. */
#pragma restore
    // clang-format on
}

/**
 * @brief Write data to FLASH by page (Operation time is about 10ms @ 16MHz)
 *
 * @param Addr Flash addr :The address must be the first address
 * of the block, such as at the end of hexadecimal 00 20 40 60 80 A0 C0 E0
 */
/* PRQA S 3206 2 # Used in assembly code. */
/* PRQA S 3408 1 #Internal variables, functions are not modified. */
void FLASH_WRITE_FUN(uint16_t Addr, uint8_t Len)
{
    // clang-format off
/* PRQA S 3116 3 # Assembly syntax. */
#pragma save
#pragma disable_warning 59
#pragma disable_warning 85
	/* PRQA S 0289, 0899, 0451, 0873, 0780, 0782, 0911, 1277 ++ #Assembly code does not conform to C rules. */
    /* PRQA S 3110, 3112, 2000, 3202, 3109, 3139, 3417, 2015, 2214, 2753, 3426, 1842 ++ #assembly syntax. */
    /* PRQA S 2741 ++ #Control via macro definitions. */
	__asm
	BANKSEL _NVMADDRH
	MOV		_NVMADDRH,R0
	BANKSEL STK00
	MOV		R0,STK00
	BANKSEL _NVMADDRL
	MOV		_NVMADDRL,R0
	MOV		R1,_INTCTL
	CLR		_INTCTL,_PUIE
	CLR		_INTCTL,_AIE
	JNB		_INTCTL,_AIE
	JMP		$-2
	MOV		R0,#0x30
    CLR     _OSCCTL,_IESO
	MOV		R7,_OSCCTL
	MOV		_OSCCTL,R0
	MOV		R2,#_writeBuffer
FALSH_WRITE_PAGE_LOOP_FLASH_WRITE_FUN:
	BANKSEL _writeBuffer
	LD		R6,[R2]
	INC		R2
	LD		R5,[R2]
	INC		R2
	CWDT
	BANKSEL _NVMDATAH
	MOV _NVMDATAL,R6
	MOV _NVMDATAH,R5
    BANKSEL _Flash_Key_ONE
	MOV 	R6,_Flash_Key_ONE
    BANKSEL _Flash_Key_TWO
	MOV 	R5,_Flash_Key_TWO
	MOV 	R0,#0x84
	BANKSEL _NVMCTL0
	MOV 	_NVMCTL0,R0
    NOP
	MOV 	_NVMCTL1,R6
    NOP
	MOV 	_NVMCTL1,R5
	SET 	_NVMCTL0 , 1
	NOPZ
	NOPZ
	NOPZ
	NOPZ
	NOPZ
	NOPZ
	NOPZ
	NOPZ
	NOPZ
	NOPZ
	MOV 	R6,#0X80
	MOV 	_NVMCTL0,R6
	INC		_NVMADDRL
	BANKSEL STK01
	DECJZ	STK01
	JMP		FALSH_WRITE_PAGE_LOOP_FLASH_WRITE_FUN
	BANKSEL _OSCCTL
	MOV		_OSCCTL,R7
    JB      R7,_SCF1
    JMP     $+7
    MOV     R0,#0x9D
    PAGESEL _Delay_2us_loop
    CALL    _Delay_2us_loop
    PAGESEL $
    DECJZ   R0
    JMP     $-4
	BANKSEL _OSCCTL
    SET     _OSCCTL,_IESO
	AND 	R1,#0xC0
	ORL 	_INTCTL,R1
__endasm;
    /* PRQA S 0289, 0899, 0451, 0873, 0780, 0782, 0911, 1277, 3110, 3112, 2000, 2741, 3202, 3109, 3417, 3139-- */
        /* PRQA S 2015, 2214, 2753, 3426, 1842-- */
/* PRQA S 3116 3 # Assembly syntax. */
#pragma restore
    // clang-format on
}
/**
 * @brief Read FLASH data and place it in the numerical value readBuffer (Operation time is about 1ms @ 16MHz)
 *
 * @param Addr Flash addr
 * @param Len Read data length
 */
/* PRQA S 3206 2 # Used in assembly code. */
/* PRQA S 3408 1 #Internal variables, functions are not modified. */
void FLASH_READ_FUN(uint16_t Addr, uint8_t Len)
{
    // clang-format off
	/* PRQA S 0289, 0899, 0451, 0873, 0780, 0782, 0911, 1277 ++ #Assembly code does not conform to C rules. */
    /* PRQA S 3110, 3112, 2000, 3202, 3109, 3139, 3417, 2015, 2214, 2753, 3426, 1842 ++ #assembly syntax. */
    /* PRQA S 2741 ++ #Control via macro definitions. */
	__asm
	BANKSEL _NVMADDRH
	MOV		_NVMADDRH,R0
	BANKSEL STK00
	MOV		R0,STK00
	BANKSEL _NVMADDRL
	MOV		_NVMADDRL,R0
	MOV		R1,_INTCTL
	CLR		_INTCTL,_AIE
	JNB		_INTCTL,_AIE
	JMP		$-2
	MOV		R0,#_readBuffer
FLASH_READ_FUN_LOOP:
	MOV 	R6,#0x81
	MOV 	_NVMCTL0,R6
	NOPZ
	NOPZ
	NOPZ
	NOPZ
	MOV	R6,_NVMDATAL
	BANKSEL _readBuffer
	ST		[R0],R6
	INC		R0
    BANKSEL	_NVMDATAH
	MOV	R6,_NVMDATAH
    BANKSEL _readBuffer
	ST		[R0],R6
	INC		R0
	BANKSEL _NVMADDRL
	INC		_NVMADDRL
	JNB		_PSW,_Z
	INC		_NVMADDRH
	BANKSEL STK01
	DECJZ	STK01
	JMP		FLASH_READ_FUN_LOOP
    BANKSEL _INTCTL
	AND 	R1,#0xC0
	ORL 	_INTCTL,R1
__endasm;
    /* PRQA S 0289, 0899, 0451, 0873, 0780, 0782, 0911, 1277, 3110, 3112, 2000, 2741, 3202, 3109, 3417, 3139-- */
        /* PRQA S 2015, 2214, 2753, 3426, 1842-- */
    // clang-format on
}
/**
 * @brief Write data to FLASH by half page
 *
 * @attention 1. This function cannot be called within an interrupt service routine.
 * 2. Write the KEY before calling the function, and clear the KEY after the function call.
 * 3. When writing to Flash, starting from the self-write address 800H of the Flash, 16 consecutive words form a data
 * block, and 2 consecutive data blocks form a page.
 * 4. When writing to Flash, regardless of whether the storage unit contains data, an erase operation must be performed
 * first. The erase operation only takes place when writing the first data block of each page, erasing all unit data on
 * that page. No erase operation occurs when writing other data blocks on the page.
 * 5. After writing the first data block of each page, the CPU will pause for 6ms to perform the erase and write
 * operations. When writing other blocks, the CPU will pause for 3ms to perform the write operation.
 *
 * @param Addr Flash addr: FLASH_ADDRESS_START~FLASH_ADDRESS_END and is a multiple of FLASH_EFFECTIVE_ADDRESS.
 * @param Buff Data pointer
 * @return Write falsh status
 */
Flash_CmdType Flash_Write_HalfPage(uint16_t Addr, const uint16_t *Buff)
{
    uint8_t       i;
    Flash_CmdType retVal = FLASH_CMD_SUCCESS;

    if (((Addr % FLASH_EFFECTIVE_ADDRESS) > 0u) || (Addr < FLASH_ADDRESS_START) || (Addr > FLASH_ADDRESS_END))
    {
        retVal = FLASH_PARAM_ERROR;
    }
    else
    {
        if (Flash_Key_ONE == 0x69U && Flash_Key_TWO == 0x96U)
        {
            for (i = 0u; i < FLASH_BUFFER_WORD_SIZE; i++)
            {
                writeBuffer[i] = Buff[i];
            }
            FLASH_WRITE_FUN(Addr, FLASH_BUFFER_WORD_SIZE);
        }
        else
        {
            retVal = FLASH_CMD_ERROR;
        }
    }
    return retVal;
}
/**
 * @brief Read half page of data from FLASH
 *
 * @attention This function cannot be called within an interrupt service routine.
 *
 * @param Addr Flash addr
 * @param Buff Data pointer
 */
void Flash_Read_HalfPage(uint16_t Addr, uint16_t *Buff)
{
    uint8_t i;
    FLASH_READ_FUN(Addr, FLASH_BUFFER_WORD_SIZE);
    for (i = 0u; i < FLASH_BUFFER_WORD_SIZE; i++)
    {
        Buff[i] = readBuffer[i];
    }
}
/* EOF */
